﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;

namespace Kea
{
    public class DataPlanJoinableBase<T> : DataPlanFilterable<T> where T : TableReaderWriter<T>, new()
    {
        internal DataPlanJoinableBase() { }

        private sealed class JoinJoinable : Joinable<T>
        {
            private readonly DataPlanBaseTRW<T> _dataPlanJoined;
            public JoinJoinable(DataPlanBaseTRW<T> dataPlanJoined) { _dataPlanJoined = dataPlanJoined; }

            internal TRWManager<T> Man = null;

            public override void Dispose()
            {
                if (Man == null) return;
                ((IDisposable)Man).Dispose();
                Man = null;
            }

            public override bool Read()
            {
                if (FirstTimeForThisKey)
                {
                    FirstTimeForThisKey = false;
                    if (Man == null)
                    {
                        Man = new TRWManager<T>(_dataPlanJoined);
                        Man.LoadIndexDetails();//move down??
                    }
                    return Man.ReadToStartOfRange(_keys);
                }
                return Man.ReadNextInRange(_keys);
            }
            public override T GetData()
            {
                return Man.Item;
            }

        }


        internal  Func<Joinable<T>> GetJoinable()
        {
            return () => new JoinJoinable(this);
        }


        public DataPlanOrdered<T> OrderBy<TKey>(Func<T, TKey> keySelector) { return OrderByProtected(keySelector, true); }

        public DataPlanOrdered<T> OrderByDescending<TKey>(Func<T, TKey> keySelector) { return OrderByProtected(keySelector, false); }



        public int Delete()
        {
            int c = 0;
            using (var tm = new TRWManager<T>(this, EditStatus.Updateable))
            {
                while (tm.ReadInternalForModification())
                {
                    tm.Delete();
                    c++;
                }
            }
            return c;
        }

        public TRWManager<T> ReadOne() { return TRWManager<T>.GetFirst(new TRWManager<T>(this)); }


        public int Write(Action<T> doAction)
        {
            int k = 0;
            using (var tm = new TRWManagerWithSaveAndNavigate<T>(this))
            {
                while (tm.Read())
                {
                    doAction(tm.Item);
                    tm.Save();
                    k++;
                }
            }
            return k;
        }

        public TRWManagerWithSaveAndNavigate<T> Write() { return new TRWManagerWithSaveAndNavigate<T>(this); }

        public TRWManagerWithSave<T> WriteOne() { return TRWManagerWithSave<T>.GetFirst(new TRWManagerWithSave<T>(this)); }

        public void WriteOne(Action<T> updateAction)
        {
            using (var m = WriteOne())
            {
                updateAction(m.Item);
                m.Save();
            }
        }



        #region Join Lookup

        public DataPlanJoined<T, T1> Join<T1>(DataPlanJoinableBase<T1> dataThing, Func<T, object> keyProvider) where T1 : TableReaderWriter<T1>, new()
        {
            return new DataPlanJoined<T, T1>()
            {
                TheEnumerable = this.SelectInternal(),
                ReaderKeyProvider = keyProvider,
                JoinProvider = dataThing.GetJoinable()
            };
        }

        public DataPlanJoined<T, TResult> Lookup<T1, TResult>(DataPlanLookupable<T1, TResult> dataThing, Func<T, object> keyProvider) where T1 : TableReaderWriter<T1>, new()
        {
            return new DataPlanJoined<T, TResult>()
            {
                TheEnumerable = this.SelectInternal(),
                ReaderKeyProvider = keyProvider,
                JoinProvider = dataThing.GetJoinableLookup()
            };
        }

        #endregion

    }
}